﻿using System;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using DocumentTrackingSystem.Models;
using DocumentTrackingSystem.Web.Service;
using System.Data.Entity.Validation;
using System.Diagnostics;

namespace DocumentTrackingSystem.Service
{
    public class Repository<T> : IRepository<T> where T : class
    {
        private bool shareContext = false;

        public Repository()
        {
            Context = new DTSEntities();
        }

        public Repository(DTSEntities context)
        {
            Context = context;
            shareContext = true;
        }

        protected DTSEntities Context = null;

        protected DbSet<T> DbSet
        {
            get { return Context.Set<T>(); }
        }

        public void Dispose()
        {
            if (shareContext && (Context != null))
                Context.Dispose();
        }

        public virtual IQueryable<T> All()
        {
            return DbSet.AsQueryable();
        }
        public virtual IQueryable<T> Top(int number, Expression<Func<T, bool>> predicate)
        {
            return DbSet.OrderByDescending(predicate).Take(number);
        }

        public virtual IQueryable<T> Filter(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Where(predicate).AsQueryable<T>();
        }

        public virtual IQueryable<T> Filter(Expression<Func<T, bool>> filter, out int total, int index = 0,
                                                  int size = 50)
        {
            int skipCount = index*size;
            var _resetSet = filter != null ? DbSet.Where(filter).AsQueryable() : DbSet.AsQueryable();
            _resetSet = skipCount == 0 ? _resetSet.Take(size) : _resetSet.Skip(skipCount).Take(size);
            total = _resetSet.Count();
            return _resetSet.AsQueryable();
        }

        public bool Contains(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Count(predicate) > 0;
        }

        public virtual T Find(params object[] keys)
        {
            return DbSet.Find(keys);
        }

        public virtual T Find(Expression<Func<T, bool>> predicate)
        {
            return DbSet.FirstOrDefault(predicate);
        }

        public virtual T Create(T TObject)
        {
            var newEntry = DbSet.Add(TObject);
            if (!shareContext)
                Context.SaveChanges();
            return newEntry;
        }

        public virtual int Count
        {
            get { return DbSet.Count(); }
        }

        public virtual int Delete(T TObject)
        {
            DbSet.Remove(TObject);
            if (!shareContext)
                return Context.SaveChanges();
            return 0;
        }


        public virtual int Update(T TObject)
        {
            try
            {
                Context.Entry(TObject).State = EntityState.Modified;
                Context.SaveChanges();
                return 0;
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName,
                        validationError.ErrorMessage);
                    }
                }
                throw;
            }
        }

        //public virtual int Update(T TObject)
        //{
        //    var entry = Context.Entry(TObject);
        //    DbSet.Attach(TObject);
        //    entry.State = EntityState.Modified;
        //    if (!shareContext)
        //        return Context.SaveChanges();
        //    return 0;
        //}

        public virtual int Delete(Expression<Func<T, bool>> predicate)
        {
            var objects = Filter(predicate);
            foreach (var obj in objects)
                DbSet.Remove(obj);
            //if (!shareContext)
                return Context.SaveChanges();
            return 0;
        }
    }

}
